/*
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */
package com.smartleanx.module.hrm.util.esign;

import cn.hutool.json.JSONObject;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.smartleanx.module.hrm.service.esign.ESignUrlConstant;
import com.smartleanx.module.hrm.util.esign.enums.EsignHeaderConstant;
import com.smartleanx.module.hrm.util.esign.enums.EsignRequestType;
import com.smartleanx.module.hrm.util.esign.exception.EsignDemoException;
import org.apache.http.entity.ByteArrayEntity;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author 澄泓
 * @version JDK1.7
 * @description 文件转换类
 * @date 2020/10/26 10:47
 */
public class FileUtil {

    //测试域名
    private static String eSignHost = "https://smlopenapi.esign.cn";


    public static String fileHTML(String filePath) throws EsignDemoException, InterruptedException {
        String fileName = filePath.substring(filePath.lastIndexOf('/') + 1);
        String fileType = "doc";
        if(fileName.contains("pdf")){
            fileType = "pdf";
        }

        JSONObject jsonObject = getUploadUrl(filePath,fileType);
        Gson gson = new Gson();
//        JsonObject getUploadUrlJsonObject = gson.fromJson(uploadUrl.getBody(), JsonObject.class);
//        JsonObject data = getUploadUrlJsonObject.getAsJsonObject("data");
        //文件id后续发起签署使用
        String fileId =jsonObject.getStr("fileId");
        String fileUploadUrl =jsonObject.getStr("fileUploadUrl");

        System.out.println("获取文件id以及文件上传地址成功，文件id:"+fileId);
        System.out.println("上传链接"+fileUploadUrl);

        //文件上传
        EsignHttpResponse uploadFileResponse = null;
        try {
            uploadFileResponse = uploadFile(fileUploadUrl,filePath,fileType);
        } catch (Exception e) {
            e.printStackTrace();
        }
        JsonObject uploadFileResponseJsonObject = gson.fromJson(uploadFileResponse.getBody(), JsonObject.class);
        String code = uploadFileResponseJsonObject.get("errCode").getAsString();
        System.out.println("文件上传成功，状态码:"+code);

        //文件上传成功后文件会有一个异步处理过程，建议轮询文件状态，正常后发起签署
        //查询文件上传状态
        getFileStatus(fileId);

        return fileId;
    }

    /**
     * 获取文件上传地址
     * @return
     */
    public static JSONObject getUploadUrl(String filePath,String fileType) throws EsignDemoException {
        //自定义的文件封装类，传入文件地址可以获取文件的名称大小,文件流等数据
        EsignFileBean esignFileBean = new EsignFileBean(filePath);
        String apiaddr= ESignUrlConstant.FILE_UPLOAD_URL;
        //请求参数body体,json格式。get或者delete请求时jsonString传空json:"{}"或者null
        JSONObject jsonObject = new JSONObject();
        jsonObject.set("contentMd5",esignFileBean.getFileContentMD5());
        jsonObject.set("fileName",esignFileBean.getFileName());
        jsonObject.set("fileSize",esignFileBean.getFileSize());
        jsonObject.set("convertToHTML",!fileType.equals("pdf"));
        jsonObject.set("contentType",fileType.equals("pdf")?EsignHeaderConstant.CONTENTTYPE_PDF.VALUE() :EsignHeaderConstant.CONTENTTYPE_STREAM.VALUE());
        String jsonParm = jsonObject.toString();

        //请求方法
        EsignRequestType requestType= EsignRequestType.POST;
        //发起接口请求
        EsignHttpResponse esignHttpResponse = ESignUtil.sendHttpResponse(jsonParm, requestType, apiaddr, eSignHost);
        Gson gson = new Gson();
        JsonObject getUploadUrlJsonObject = gson.fromJson(esignHttpResponse.getBody(), JsonObject.class);
        JsonObject data = getUploadUrlJsonObject.getAsJsonObject("data");
        //文件id后续发起签署使用
        String fileId =data.get("fileId").getAsString();
        String fileUploadUrl =data.get("fileUploadUrl").getAsString();

        JSONObject result = new JSONObject();
        result.set("fileId",fileId);
        result.set("fileUploadUrl",fileUploadUrl);
        result.set("esignFileBean",esignFileBean);
        try {
            byte[] fileBytes = esignFileBean.getFileBytes();
            result.set("byte64",fileBytes);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 文件流上传
     * @return
     */
    public static EsignHttpResponse uploadFile(String uploadUrl,String filePath,String fileType) throws Exception {
        //根据文件地址获取文件contentMd5
        EsignFileBean esignFileBean = new EsignFileBean(filePath);
        //请求方法
        EsignRequestType requestType= EsignRequestType.PUT;
        String contentType = fileType.equals("pdf")?EsignHeaderConstant.CONTENTTYPE_PDF.VALUE() :EsignHeaderConstant.CONTENTTYPE_STREAM.VALUE();
        return EsignHttpHelper.doUploadHttp(uploadUrl,requestType,esignFileBean.getBytesFromUrl(filePath),esignFileBean.getFileContentMD5(), contentType,true);
    }


    /**
     * 获取文件上传状态
     */
    public static EsignHttpResponse getFileStatus(String fileId) throws EsignDemoException, InterruptedException {
        Gson gson = new Gson();
        String apiaddr="/v3/files/"+fileId;
        //请求参数body体,json格式。get或者delete请求时jsonString传空json:"{}"或者null
        String jsonParm=null;
        //请求方法
        EsignRequestType requestType= EsignRequestType.GET;
        EsignHttpResponse fileStatus = null;
        int i=0;
        while(i<3) {
            //发起接口请求
            fileStatus = ESignUtil.sendHttpResponse(jsonParm, requestType, apiaddr, eSignHost);

            JsonObject fileStatusJsonObject = gson.fromJson(fileStatus.getBody(), JsonObject.class);
            String status = fileStatusJsonObject.getAsJsonObject("data").get("fileStatus").getAsString();
            System.out.println(String.format("查询文件状态执行第%s次",i+1));
            if("2".equalsIgnoreCase(status)||"5".equalsIgnoreCase(status)){//查询状态为2或者5代表文件准备完成
                System.out.println("文件准备完成");
                break;
            }
            System.out.println("文件未准备完成,等待两秒重新查询");
            TimeUnit.SECONDS.sleep(2);
            i++;
        }

        return fileStatus;
    }

    /**
     * 获取HTML文件填写后的 下载地址
     */
    public static String getFileHTMLFileDownloadUrl(String fileId) throws EsignDemoException, InterruptedException {
        Gson gson = new Gson();
        int i=0;
        while(i<3) {
            EsignHttpResponse fileStatus = FileUtil.getFileStatus(fileId);
            JsonObject fileStatusJsonObject = gson.fromJson(fileStatus.getBody(), JsonObject.class);
            String status = fileStatusJsonObject.getAsJsonObject("data").get("fileStatus").getAsString();
            if("2".equalsIgnoreCase(status)||"5".equalsIgnoreCase(status)){//查询状态为2或者5代表文件准备完成
                return fileStatusJsonObject.get("data").getAsJsonObject().get("fileDownloadUrl").getAsString();
            }
            System.out.println("文件未准备完成,等待两秒重新查询");
            TimeUnit.SECONDS.sleep(2);
            i++;
        }
        return "";
    }

    /**
     * 网络图片转Base64存储，大文件勿用
     *
     * @param imageUrl 网络图片地址
     * @return BASE64
     */
    public static String convertImageUrlToBase64(String imageUrl) throws IOException {
        // 打开URL连接
        URL url = new URL(imageUrl);
        URLConnection connection = url.openConnection();
        connection.setConnectTimeout(5000); // 设置连接超时时间
        connection.setReadTimeout(5000); // 设置读取超时时间

        // 读取图片数据
        try (InputStream inputStream = connection.getInputStream();
             ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {

            byte[] buffer = new byte[4096];
            int bytesRead;

            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }

            // 将图片数据转换为Base64
            byte[] imageBytes = outputStream.toByteArray();
            return Base64.getEncoder().encodeToString(imageBytes);
        }
    }
}
